package pl.wroc.pwr.mss.server.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import pl.wroc.pwr.mss.logic.domain.AbstractEntity;
import pl.wroc.pwr.mss.server.dao.GenericDao;

/**
 * Implementacja generycznego DAO.
 * 
 * @author mjagus
 *
 * @param <T> Typ encji ktora dao ma obslugiwac
 * @param <I> Typ identyfikatora encji
 */
public class GenericDaoImpl<T extends AbstractEntity, I extends Serializable> extends HibernateDaoSupport implements GenericDao<T, I>
{
    /**
     * Klasa encji dla tego DAO.
     */
    private Class<? extends T> clazz;

    /**
     * Iniciuje DAO dla danej klasy encji.
     * 
     * @param clazz Klasa encji
     */
    public GenericDaoImpl(Class<? extends T> clazz)
    {
        this.clazz = clazz;
    }

    /**
     * Iniciuje DAO dla zadanej fabryki sesji hibernate'a.
     * 
     * @param sessionFactory Fabryka sesji hibernate'a.
     */
    @SuppressWarnings("unchecked")
    public GenericDaoImpl(SessionFactory sessionFactory)
    {
        ParameterizedType thisType = (ParameterizedType)this.getClass().getGenericSuperclass();
        this.clazz = (Class<? extends T>)thisType.getActualTypeArguments()[0];
        super.setSessionFactory(sessionFactory);
    }

    @Override
    public T findById(I id)
    {
        if(id != null)
        {
            T entity = (T)getHibernateTemplate().get(clazz, id);
            return entity;
        }
        else
            return null;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<T> findAll()
    {
        return (List<T>)getHibernateTemplate().loadAll(clazz);
    }

    @Override
    public int countAll()
    {
        return DataAccessUtils.intResult(getHibernateTemplate().find("select count(*) from " + getClassName()));
    }

    @Override
    public void remove(T entity)
    {
        getHibernateTemplate().delete(entity);
    }

    @Override
    public T save(T entity)
    {
        return getHibernateTemplate().merge(entity);
    }

    @Override
    public String getClassName() {
        return clazz.getSimpleName();
    }

    @Override
    public boolean entityByFieldExists(String field, String value)
    {
        Criteria criteria = super.getSessionFactory().getCurrentSession().createCriteria(clazz);
        criteria.add(Restrictions.eq(field, value));

        return !criteria.list().isEmpty();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<T> findEntityByFieldValue(String field, String value)
    {
        Criteria criteria = super.getSessionFactory().getCurrentSession().createCriteria(clazz);
        criteria.add(Restrictions.eq(field, value));

        return criteria.list();
    }

}
